package net.kleinhenz.norabase.server;

import java.io.File;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import net.kleinhenz.norabase.server.model.Champ;
import net.kleinhenz.norabase.server.model.Equip;
import net.kleinhenz.norabase.server.model.Runes;
import net.kleinhenz.norabase.shared.model.Ability;
import net.kleinhenz.norabase.shared.model.Champion;
import net.kleinhenz.norabase.shared.model.Equipment;
import net.kleinhenz.norabase.shared.model.Relic;
import net.kleinhenz.norabase.shared.model.Rune;
import net.kleinhenz.norabase.shared.model.Spell;

public class PoxNoraXMLReader {

	private static List<Champion> champions = new ArrayList<Champion>();
	private static List<Spell> spells = new ArrayList<Spell>();
	private static List<Equipment> equipments = new ArrayList<Equipment>();
	private static List<Relic> relics = new ArrayList<Relic>();
	
	private static JAXBContext jc = null;
    private static Unmarshaller unmarshaller = null;
	
	static {
		
		// parse XML
		Runes runesXML = null;
	    try {
			if (jc==null)
				jc = JAXBContext.newInstance("net.kleinhenz.norabase.server.model");

			if (unmarshaller==null)
				unmarshaller = jc.createUnmarshaller();

			runesXML = (Runes)unmarshaller.unmarshal(new File("WEB-INF/poxnora.xml"));
		} catch (JAXBException e) {
			throw new RuntimeException(e);
		}
		
		// copy into sane model
		champions.clear();
		for (Champ cXML : runesXML.getChampions().getChamp()) 
			champions.add(copyChampion(cXML));

		spells.clear();
		for (net.kleinhenz.norabase.server.model.Spell sXML : runesXML.getSpells().getSpell()) 
			spells.add(copySpell(sXML));

		equipments.clear();
		for (Equip eXML : runesXML.getEquipment().getEquip()) 
			equipments.add(copyEquipment(eXML));

		relics.clear();
		for (net.kleinhenz.norabase.server.model.Relic rXML : runesXML.getRelics().getRelic()) 
			relics.add(copyRelic(rXML));
	}
	
	public static List<Champion> getChampions() {
		return champions;
	}

	public static List<Spell> getSpells() {
		return spells;
	}

	public static List<Equipment> getEquipments() {
		return equipments;
	}

	public static List<Relic> getRelics() {
		return relics;
	}

	public static Rune getRune(Integer id, String type) {
		
		if (Rune.CHAMPION.equals(type))
			return searchRune(getChampions(), id);
		else if (Rune.EQUIPMENT.equals(type))
			return searchRune(getEquipments(), id);
		else if (Rune.SPELL.equals(type))
			return searchRune(getSpells(), id);
		else if (Rune.RELIC.equals(type))
			return searchRune(getRelics(), id);
		else
			return null;
	}
	
	public static Champion getChampion(int id) {
		return (Champion)searchRune(getChampions(), id);
	}

	public static Spell getSpell(int id) {
		return (Spell)searchRune(getSpells(), id);
	}

	public static Equipment getEquipment(int id) {
		return (Equipment)searchRune(getEquipments(), id);
	}

	public static Relic getRelic(int id) {
		return (Relic)searchRune(getRelics(), id);
	}

	public static Rune searchRune(String type, String name, String expansion) {
		if (Rune.CHAMPION.equals(type))
			return searchRune(getChampions(), name, expansion);
		else if (Rune.EQUIPMENT.equals(type))
			return searchRune(getEquipments(), name, expansion);
		else if (Rune.SPELL.equals(type))
			return searchRune(getSpells(), name, expansion);
		else if (Rune.RELIC.equals(type))
			return searchRune(getRelics(), name, expansion);
		else
			return null;
	}

	private static Rune searchRune(List<? extends Rune> runes, String name, String expansion) {
		for (Rune r : runes)
			if (r.getName().equals(name) && r.getExpansion().equals(expansion))
				return r;
		return null;
	}

	private static Rune searchRune(List<? extends Rune> runes, int id) {
		for (Rune r : runes)
			if (r.getId()==id)
				return r;
		return null;
	}

	@SuppressWarnings("rawtypes")
	private static Relic copyRelic(net.kleinhenz.norabase.server.model.Relic rel) {

		Relic relic = new Relic();
		for (Object o : rel.getContent()) {
			if (o instanceof JAXBElement) {
				String key = ((JAXBElement)o).getName().toString();
				Object value = ((JAXBElement)o).getValue();
				
				if ("allow_ranked".equals(key))
					relic.setAllowRanked(((Boolean)value).booleanValue());
				else if ("artist".equals(key))
					relic.setArtist(((String)value));
				else if ("def".equals(key))
					relic.setDef(((BigInteger)value).intValue());
				else if ("desc".equals(key))
					relic.setDesc(((String)value));
				else if ("expansion".equals(key))
					relic.setExpansion(((String)value));
				else if ("faction".equals(key))
					relic.setFaction(((String)value));
				else if ("forsale".equals(key))
					relic.setForsale(((Boolean)value).booleanValue());
				else if ("hp".equals(key))
					relic.setHp(((BigInteger)value).intValue());
				else if ("id".equals(key))
					relic.setId(((BigInteger)value).intValue());
				else if ("name".equals(key))
					relic.setName(((String)value));
				else if ("nora".equals(key))
					relic.setNora(((BigInteger)value).intValue());
				else if ("rarity".equals(key))
					relic.setRarity(((BigInteger)value).intValue());
				else if ("relic".equals(key))
					relic.setRelic(((BigInteger)value).intValue());
				else if ("tradable".equals(key))
					relic.setTradeable(((Boolean)value).booleanValue());
			}
		}
		
		return relic;
	}

	private static Equipment copyEquipment(Equip equip) {

		Equipment equipment = new Equipment();
		equipment.setAllowRanked(equip.isAllowRanked());
		equipment.setArtist(equip.getArtist());
		equipment.setDesc(equip.getDesc());
		equipment.setExpansion(equip.getExpansion());
		equipment.setFaction(equip.getFaction());
		equipment.setForsale(equip.isForsale());
		equipment.setId(equip.getId().intValue());
		equipment.setName(equip.getName());
		equipment.setNora(equip.getNora().intValue());
		equipment.setRarity(equip.getRarity().intValue());
		equipment.setTradeable(equip.isTradable());

		return equipment;
	}

	private static Spell copySpell(net.kleinhenz.norabase.server.model.Spell sp) {

		Spell spell = new Spell();
		spell.setAllowRanked(sp.isAllowRanked());
		spell.setArtist(sp.getArtist());
		spell.setDesc(sp.getDesc());
		spell.setExpansion(sp.getExpansion());
		spell.setFaction(sp.getFaction());
		spell.setForsale(sp.isForsale());
		spell.setId(sp.getId().intValue());
		spell.setName(sp.getName());
		spell.setNora(sp.getNora().intValue());
		spell.setRarity(sp.getRarity().intValue());
		spell.setTradeable(sp.isTradable());
		spell.setCooldown(sp.getCooldown().intValue());
		
		return spell;
	}

	private static Champion copyChampion(Champ champ) {

		Champion champion = new Champion();
		champion.setAllowRanked(champ.isAllowRanked());
		champion.setArtist(champ.getArtist());
		champion.setClasses(champ.getClasses());
		champion.setDef(champ.getDef().intValue());
		champion.setDmg(champ.getDmg().intValue());
		champion.setExpansion(champ.getExpansion());
		champion.setFaction(champ.getFaction());
		champion.setForsale(champ.isForsale());
		champion.setHp(champ.getHp().intValue());
		champion.setId(champ.getId().intValue());
		champion.setMaxrng(champ.getMaxrng().intValue());
		champion.setMinrng(champ.getMinrng().intValue());
		champion.setName(champ.getName());
		champion.setNora(champ.getNora().intValue());
		champion.setRaces(champ.getRaces());
		champion.setRarity(champ.getRarity().intValue());
		champion.setSize(champ.getSize());
		champion.setSpd(champ.getSpd().intValue());
		champion.setTradeable(champ.isTradeable());
		champion.setStartingAbilities(copyAbilities(champ.getStartingAbilities().getAbility()));
		champion.setUpgradeAbilities(copyAbilities(champ.getUpgradeAbilities().getAbility()));

		return champion;
	}

	private static List<Ability> copyAbilities(List<net.kleinhenz.norabase.server.model.Ability> abs) {

		List<Ability> abilities = new ArrayList<Ability>();
		for (net.kleinhenz.norabase.server.model.Ability a : abs) {
			Ability ability = new Ability();
			ability.setAp(a.getAp().intValue());
			ability.setCooldown(a.getCooldown().intValue());
			ability.setDesc(a.getDesc());
			ability.setId(a.getId().intValue());
			ability.setName(a.getName());
			ability.setRank(a.getRank().intValue());
			ability.setType(a.getType().intValue());
			abilities.add(ability);
		}

		return abilities;
	}
}
